/*
 * FactoryMethodPersistenceDelegate.java
 *
 * Created on May 27, 2004, 4:57 PM
 *
 * Copyright 2008 the Desert Labs Project (http://desertlabs.us)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package us.desertlabs.beans;

import java.beans.Encoder;
import java.beans.Expression;
import java.beans.PersistenceDelegate;
import java.util.HashMap;
import java.util.Map;

/**
 * This class represents a <CODE>PersistenceDelegate</CODE> for <CODE>Object</CODE>s
 * that are instantiated via a static factory method.
 *
 * @author Brian Franklin
 */
public class FactoryMethodPersistenceDelegate extends PersistenceDelegate {

    /** Empty <CODE>Object</CODE> array */
    static private final Object[] EMPTY_ARRAY = new Object[0];

    /** The default factory method name */
    static protected final String DEFAULT_FACTORY_METHOD_NAME = "getInstance";

    /** Singleton instances */
    static protected final Map<String, FactoryMethodPersistenceDelegate> instanceMap = new HashMap<String, FactoryMethodPersistenceDelegate>();

    /**
     * Returns the singleton instance with the default factory method name. The
     * default factory method name is "<CODE>getInstance</CODE>".
     *
     * @return the singleton instance
     */
    static public FactoryMethodPersistenceDelegate getInstance() {
        return getInstance( DEFAULT_FACTORY_METHOD_NAME );
    }

    /**
     * Returns the singleton instance with the specified factory method name.
     *
     * @param methodName the name of the factory method used during
     *        instantiation
     * @return the singleton instance
     */
    static synchronized public FactoryMethodPersistenceDelegate getInstance( final String methodName ) {
        FactoryMethodPersistenceDelegate instance = instanceMap.get( methodName );
        if( instance == null ) {
            instance = new FactoryMethodPersistenceDelegate( methodName );
            instanceMap.put( methodName, instance );
        }
        return instance;
    }

    /** The factory method to use during instantiation */
    protected String methodName = null;

    /**
     * Creates a new instance of <CODE>FactoryMethodPersistenceDelegate</CODE>
     * that uses the specified factory method name for object instantiation.
     * This constructor is not public because of the singleton implementation,
     * but it is protected so that subclasses can be constructed if necessary.
     *
     * @param methodName the name of the factory method used during
     *        instantiation
     */
    protected FactoryMethodPersistenceDelegate( final String methodName ) {
        this.methodName = methodName;
    }

    /**
     * Returns an <CODE>Expression</CODE> that instantiates the object by
     * passing the value returned from its <CODE>toString</CODE> method to its
     * constructor.
     *
     * @param obj the instance that will be created by this expression
     * @param encoder the stream to which this expression will be written
     * @return an <CODE>Expression</CODE> whose value is <CODE>obj</CODE>
     */
    @Override
    protected Expression instantiate( final Object obj, final Encoder encoder ) {
        return new Expression( obj, obj.getClass(), methodName, EMPTY_ARRAY );
    }
}
